﻿using Fluffy.Library.DocumentContainer;
using Fluffy.Library.Mvvm;
using Fluffy.Library.Utils;
using ICSharpCode.AvalonEdit;
using ICSharpCode.AvalonEdit.Highlighting;
using System.Text;
using System.Windows;
using System.Windows.Input;

namespace Fluffy.Text
{
	public class TextDocumentViewModel : DocumentViewModelBase
	{
		private readonly TextDocumentModel _model;
		private readonly Command _undoCommand;
		private readonly Command _redoCommand;

		private TextEditor _textEditor;
		private Encoding _encoding = Encoding.Default;
		private IHighlightingDefinition _highlightingDefinition;

		internal TextDocumentViewModel(TextDocumentModel model)
		{
			_model = model;

			_highlightingDefinition = HighlightingManager.Instance.GetDefinitionByExtension(_model.FomatExtension);

			_undoCommand = new Command(() => _textEditor.Undo(), () => _textEditor.CanUndo);
			_redoCommand = new Command(() => _textEditor.Redo(), () => _textEditor.CanRedo);
		}

		public IHighlightingDefinition HighlightingStyle
		{
			get { return _highlightingDefinition; }
			set
			{
				if (_highlightingDefinition == value)
					return;

				_highlightingDefinition = value;
				OnPropertyChanged("HighlightingStyle");
			}
		}
		
		public override ICommand CutCommand
		{
			get { return new Command(() => _textEditor.Cut()); }
		}

		public override ICommand CopyCommand
		{
			get { return new Command(() => _textEditor.Copy()); }
		}

		public override ICommand PasteCommand
		{
			get { return new Command(() => _textEditor.Paste()); }
		}

		public override ICommand SaveCommand
		{
			get { return new Command(OnSave); }
		}

		public override ICommand SaveAsCommand
		{
			get { return new Command(OnSaveAs); }
		}

		public TextEditor TextEditor
		{
			get { return _textEditor; }
			set
			{
				if (Equals(_textEditor, value))
				{
					return;
				}

				string text;
				if (_textEditor != null)
				{
					_textEditor.TextChanged -= OnTextChanged;
					text = _textEditor.Text;
				}
				else
				{
					text = _model.GetText(_encoding);
				}

				_textEditor = value;

				if (_textEditor != null)
				{
					_textEditor.Text = text;
					_textEditor.IsModified = false;
					_textEditor.TextChanged += OnTextChanged;
				}
			}
		}

		private void OnSave()
		{
			if (_model.IsNewFile)
			{
				OnSaveAs();
			}
			else
			{
				_model.SaveText(_textEditor.Text);	
			}
		}

		private void OnSaveAs()
		{
			string path = PathUtils.SelectFileForSave("Save As");

			if (string.IsNullOrEmpty(path))
				return;

			_model.SaveTextAs(path, _textEditor.Text);
		}

		public override CommandsContainer Menu1
		{
			get
			{
				CommandsContainer commandsContainer = new CommandsContainer("Text");
				commandsContainer.Children.Add(new CommandItem("Undo", _undoCommand));
				commandsContainer.Children.Add(new CommandItem("Redo", _redoCommand));
				return commandsContainer;
			}
		}

		public override CommandsContainer Menu2
		{
			get
			{
				CommandsContainer commandsContainer = new CommandsContainer("Encoding");
				foreach (EncodingInfo encoding in Encoding.GetEncodings())
				{
					Encoding item = encoding.GetEncoding();
					commandsContainer.Children.Add(new CommandItem(encoding.DisplayName, new Command(() => SetEncoding(item))));	
				}
				
				return commandsContainer;
			}
		}

		public override CommandsContainer Menu3
		{
			get
			{
				CommandsContainer commandsContainer = new CommandsContainer("Highlighting");
				for (int index = 0; index < HighlightingManager.Instance.HighlightingDefinitions.Count; index++)
				{
					IHighlightingDefinition definition = HighlightingManager.Instance.HighlightingDefinitions[index];
					commandsContainer.Children.Add(new CommandItem(definition.Name, new Command(() => HighlightingStyle = definition)));
				}
				commandsContainer.Children.Add(new CommandItem("Simple Text", new Command(() => HighlightingStyle = null)));

				return commandsContainer;
			}
		}

		public void OnTextChanged(object sender, System.EventArgs e)
		{
			_undoCommand.RaiseCanExecuteChanged();
			_redoCommand.RaiseCanExecuteChanged();
		}

		private void SetEncoding(Encoding encoding)
		{
			if (_textEditor.IsModified)
			{
				MessageBoxResult result = MessageBox.Show("The text is modificated. If you will change encoding you will miss all changes. Do you want to continue?", "Fluffy", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
				if (result == MessageBoxResult.Cancel)
					return;
			}

			_encoding = encoding;

			_textEditor.Clear();
			_textEditor.Text = _model.GetText(_encoding);
			_textEditor.IsModified = false;
		}

		public override void Close()
		{
			TextEditor = null;
		}
	}
}
